Skip to content

C#: Reduce false positives in cs/web/missing-x-frame-options - #22553

Open
Bubby4j wants to merge 1 commit into
github:mainfrom
Bubby4j:fix/cs-missing-x-frame-options
Open

Bubby4j wants to merge 1 commit into
github:mainfrom
Bubby4j:fix/cs-missing-x-frame-options

Conversation

@Bubby4j

@Bubby4j Bubby4j commented Sep 11, 2026

Copy link
Copy Markdown

Summary

The cs/web/missing-x-frame-options query was primarily modeled around legacy ASP.NET Framework applications hosted by IIS. As a result, it could report false positives for ASP.NET Core applications that correctly configure clickjacking-related response headers in code.

This change:

  • recognizes X-Frame-Options written through ASP.NET Core HttpResponse.Headers
  • recognizes enforced Content-Security-Policy headers containing a frame-ancestors directive
  • supports header dictionary indexers, named header properties, and Append, Add, and TryAdd
  • handles header names and CSP directive names case-insensitively

Legacy ASP.NET Framework and Web.config handling remains supported.

Testing

  • Added positive and negative tests for ASP.NET Core response-header writes.
  • Added Web.config tests for CSP frame-ancestors handling.

@github-actions

Copy link
Copy Markdown
Contributor

QHelp previews:

csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.qhelp

Missing clickjacking protection

Web sites that do not restrict framing using the X-Frame-Options HTTP header or the frame-ancestors Content Security Policy directive may be vulnerable to UI redress attacks ("clickjacking"). In these attacks, the vulnerable site is loaded in a frame on an attacker-controlled site which uses opaque or transparent layers to trick the user into unintentionally clicking a button or link on the vulnerable site.

Recommendation

Set the X-Frame-Options HTTP header to DENY, to instruct web browsers to block attempts to load the site in a frame. Alternatively, if framing is needed in certain circumstances, specify SAMEORIGIN to permit framing by the same origin. The frame-ancestors directive in an enforced Content-Security-Policy header provides a more flexible alternative. For example, use frame-ancestors 'none' to prevent all framing, or use its source list to specify which origins may embed the application.

For ASP.NET Framework applications, the header may be specified either in the Web.config file, using the <customHeaders> tag, or within the source code of the application using the HttpResponse.AddHeader method. In general, prefer specifying the header in the Web.config file to ensure it is added to all requests. If adding it to the source code, ensure that it is added unconditionally to all requests. For example, add the header in the Application_BeginRequest method in the global.asax file.

For ASP.NET Core applications, set the header on HttpResponse.Headers. This can be done using the header dictionary's indexer or its Append, Add, or TryAdd methods.

Example

The following example shows how to specify the X-Frame-Options header within the Web.config file for ASP.NET:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.web>
  </system.web>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="X-Frame-Options" value="SAMEORIGIN" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

This next example shows how to specify the X-Frame-Options header within the global.asax file for an ASP.NET application:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    HttpContext.Current.Response.AddHeader("X-Frame-Options", "DENY");
}

The following ASP.NET Core example uses an enforced Content Security Policy to disallow framing:

void Configure(IApplicationBuilder app)
{
    app.Use(async (context, next) =>
    {
        context.Response.Headers["Content-Security-Policy"] = "frame-ancestors 'none'";
        await next();
    });
}

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants